//+------------------------------------------------------------------+
//|                                                          Slave.mq5 |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#include <Trade/Trade.mqh>

// 输入参数
input int      SafetyMargin = 0;           // 安全保证金点数
input double   OrderSize = 0.1;            // 订单手数
input int      OrderCount = 1;             // 订单数量
input double   RiskManagement = 10.0;      // 风险管理百分比
input bool     UseECN = false;             // 使用ECN模式
input int      ExtraStopLoss = 0;          // 额外止损点数
input bool     DebugMode = false;          // 启用调试模式

// 全局变量
string         ExpertName = "Slave";       // 专家顾问名称
int            MagicNumber = 2;            // 魔术数字
double         PipsThreshold = 4.0;        // 点数阈值
double         RiskMultiplier = 1.0;       // 风险乘数
bool           UseDynamicOrderSize = false;// 使用动态订单大小
double         RiskThreshold = 10.0;       // 风险阈值
double         PriceAdjustment = 0.0;      // 价格调整
bool           IsPriceAdjusted = false;    // 价格是否已调整
int            PricePrecision = 1;         // 价格精度
string         SymbolName = "";            // 交易品种名称
string         SymbolSuffix = "";          // 交易品种后缀
double         StopLevel = -1.0;           // 止损水平
int            ExpertHash = 110;           // 专家顾问哈希值
int            PriceUpdateCount = 0;       // 价格更新计数
int            LastPriceUpdateCount = -1;  // 上次价格更新计数
double         CurrentAsk;                 // 当前卖价
double         CurrentBid;                 // 当前买价
double         LastPriceDiff = 1.0;        // 上次价格差异
string         LogPath = "MetaTrader (MASTER)\\experts\\files"; // 日志文件路径

// 订单相关全局变量
double         LastOrderPrice = -1.0;      // 最后订单价格
ENUM_ORDER_TYPE LastOrderType;             // 最后订单类型
int            priceMovementArray[20];     // 价格移动数组

//+------------------------------------------------------------------+
//| 专家顾问初始化函数                                               |
//+------------------------------------------------------------------+
int OnInit()
{
    // 根据账户余额计算风险阈值
    RiskThreshold = (1 - RiskManagement / 100.0) * AccountInfoDouble(ACCOUNT_BALANCE);
    
    // 计算专家顾问哈希值用于订单识别
    ExpertHash = 0;
    for(int i = StringLen(ExpertName); i > 0; i--)
        ExpertHash += StringGetCharacter(ExpertName, i);
    
    // 初始化交易品种名称
    SymbolName = _Symbol;
    Print("开始运行: 交易品种=", SymbolName);
     Print("当前工作目录: ", TerminalInfoString(TERMINAL_DATA_PATH));
    
    // 计算止损水平
    StopLevel = SymbolInfoInteger(SymbolName, SYMBOL_TRADE_STOPS_LEVEL) + ExtraStopLoss;
    
    // 初始化当前价格
    CurrentAsk = SymbolInfoDouble(SymbolName, SYMBOL_ASK);
    CurrentBid = SymbolInfoDouble(SymbolName, SYMBOL_BID);
    
    // 初始化价格移动数组
    ArrayInitialize(priceMovementArray, 0);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 专家顾问反初始化函数                                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // 清理资源
    if(reason == REASON_RECOMPILE || reason == REASON_REMOVE)
    {
        // 关闭所有打开的订单
        CloseOpenOrders(SymbolName, CalculateMagicNumber(ExpertHash));
    }
}

//+------------------------------------------------------------------+
//| 专家顾问主函数                                                   |
//+------------------------------------------------------------------+
void OnTick()
{
    // 更新当前价格
    double newAsk = SymbolInfoDouble(SymbolName, SYMBOL_ASK);
    double newBid = SymbolInfoDouble(SymbolName, SYMBOL_BID);
    
    // 检查价格是否发生变化
    if(CurrentAsk != newAsk || CurrentBid != newBid)
    {
        CurrentAsk = newAsk;
        CurrentBid = newBid;
        PriceUpdateCount++;
    }
    
    // 获取当前时间并调整时区
    datetime currentTime = TimeLocal();
    currentTime -= 18000; // 调整时区
    
    // 创建时间结构体
    MqlDateTime timeStruct;
    TimeToStruct(currentTime, timeStruct);
    
    // 创建日志文件名
    string logFileName = StringFormat("%s\\log__%s_%04d-%02d-%02d.csv",
        LogPath,
        StringSubstr(SymbolName, 0, 6),
        timeStruct.year,
        timeStruct.mon,
        timeStruct.day);
    
    Print("日志文件名: ", logFileName);
    // 打开日志文件
    int fileHandle = FileOpen(logFileName, FILE_CSV|FILE_READ);
    if(fileHandle == INVALID_HANDLE)
    {
        Sleep(10);
        return;
    }
    
    // 检查文件是否发生变化
    int fileSize = FileSize(fileHandle);
    Print("文件大小: ", fileSize);
    if(fileSize != LastPriceUpdateCount || PriceUpdateCount != LastPriceUpdateCount)
    {
        if(fileSize != LastPriceUpdateCount)
        {
            // 从文件读取新数据
            FileSeek(fileHandle, LastPriceUpdateCount, SEEK_SET);
            string masterPriceStr = FileReadString(fileHandle);
            string slavePriceStr = FileReadString(fileHandle);
            
            double masterPrice = StringToDouble(masterPriceStr);
            if(masterPrice == 0.0)
            {
                Print("无价格数据可用");
                FileClose(fileHandle);
                return;
            }
            
            // 计算当前市场价格
            double currentPrice = (CurrentBid + CurrentAsk) / 2.0;
            if(StringFind(SymbolName, "GBPUSD") != -1)
                currentPrice = 10.0 * MathRound(currentPrice / SymbolInfoDouble(SymbolName, SYMBOL_POINT) / 10.0) * SymbolInfoDouble(SymbolName, SYMBOL_POINT);
            
            // 计算价格差异
            double priceDiff = MathAbs(currentPrice - masterPrice);
            double lastPriceDiff = MathAbs(LastPriceDiff - currentPrice);
            
            // 计算价格移动点数
            int priceMovement = (int)((currentPrice - masterPrice) / SymbolInfoDouble(SymbolName, SYMBOL_POINT));
            if(StringFind(SymbolName, "GBPUSD") != -1)
                priceMovement = (int)MathRound(priceMovement / 10.0);
            priceMovement += 10;
            
            // 计算点差
            int spread = (int)MathRound((CurrentAsk - CurrentBid) / SymbolInfoDouble(SymbolName, SYMBOL_POINT));
            
            // 记录市场分析
            if(DebugMode)
            {
                Print("价格分析:",
                    "\n上次价格差异: ", priceDiff,
                    "\n主价格: ", masterPrice,
                    "\n从价格: ", currentPrice,
                    "\n安全保证金: ", SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT),
                    "\n价格移动: ", priceMovement - 10,
                    "\n点差: ", spread);
            }
            
            // 检查价格差异是否超过阈值
            if(priceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT) || LastPriceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT))
            {
                Log(StringFormat("主价格: %.5f, 从价格: %.5f, 延迟: %.5f, 从跳跃: %.5f",
                    masterPrice, currentPrice, currentPrice - masterPrice, lastPriceDiff));
            }
            
            LastPriceDiff = priceDiff;
            
            // 检查价格移动是否过大
            if(priceMovement - ArraySize(priceMovementArray) / 2 > 9 || priceMovement - ArraySize(priceMovementArray) / 2 < -9)
            {
                IsPriceAdjusted = false;
                PriceAdjustment = 0;
                ArrayInitialize(priceMovementArray, 0);
            }
            
            // 检查是否需要调整价格
            if((priceMovementArray[priceMovement] > 10 && !IsPriceAdjusted) || priceMovementArray[priceMovement] > 20)
            {
                PriceAdjustment -= priceMovement - 10;
                IsPriceAdjusted = true;
                ArrayInitialize(priceMovementArray, 0);
            }
            
            // 检查是否应该开仓
            if(priceDiff >= SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT) && lastPriceDiff == 0.0 && LastOrderPrice == -1.0 && IsPriceAdjusted)
            {
                Log(StringFormat("开仓 - 主价格: %.5f, 从价格: %.5f, 延迟: %.5f",
                    masterPrice, currentPrice, currentPrice - masterPrice));
                
                // 开多仓
                if(masterPrice > currentPrice && priceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT))
                {
                    double orderPrice = CurrentAsk;
                    int errorCount = 0;
                    
                    while(masterPrice > currentPrice && priceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT) && errorCount < 1)
                    {
                        Log(StringFormat("当前点差: %d, 之前点差: %d",
                            (int)SymbolInfoInteger(SymbolName, SYMBOL_SPREAD),
                            spread));
                            
                        if(UseDynamicOrderSize)
                        {
                            double dynamicOrderSize = GetMaxOrderSize(0);
                            if(SendOrder(SymbolName, ORDER_TYPE_BUY, dynamicOrderSize, orderPrice,
                                orderPrice - (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount))
                            {
                                for(int i = 1; i < OrderCount; i++)
                                {
                                    SendOrder(SymbolName, ORDER_TYPE_BUY, dynamicOrderSize, orderPrice,
                                        orderPrice - (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount);
                                }
                                LastOrderPrice = orderPrice;
                                LastOrderType = ORDER_TYPE_BUY;
                                break;
                            }
                        }
                        else
                        {
                            if(SendOrder(SymbolName, ORDER_TYPE_BUY, OrderSize, orderPrice,
                                orderPrice - (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount))
                            {
                                for(int i = 1; i < OrderCount; i++)
                                {
                                    SendOrder(SymbolName, ORDER_TYPE_BUY, OrderSize, orderPrice,
                                        orderPrice - (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount);
                                }
                                LastOrderPrice = orderPrice;
                                LastOrderType = ORDER_TYPE_BUY;
                                break;
                            }
                        }
                        
                        currentPrice = (CurrentBid + CurrentAsk) / 2.0;
                        priceDiff = MathAbs(currentPrice - masterPrice);
                    }
                }
                
                // 开空仓
                if(masterPrice < currentPrice && priceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT))
                {
                    double orderPrice = CurrentBid;
                    int errorCount = 0;
                    
                    while(masterPrice < currentPrice && priceDiff > SafetyMargin * SymbolInfoDouble(SymbolName, SYMBOL_POINT) && errorCount < 1)
                    {
                        Log(StringFormat("当前点差: %d, 之前点差: %d",
                            (int)SymbolInfoInteger(SymbolName, SYMBOL_SPREAD),
                            spread));
                            
                        if(UseDynamicOrderSize)
                        {
                            double dynamicOrderSize = GetMaxOrderSize(1);
                            if(SendOrder(SymbolName, ORDER_TYPE_SELL, dynamicOrderSize, orderPrice,
                                orderPrice + (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount))
                            {
                                for(int i = 1; i < OrderCount; i++)
                                {
                                    SendOrder(SymbolName, ORDER_TYPE_SELL, dynamicOrderSize, orderPrice,
                                        orderPrice + (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount);
                                }
                                LastOrderPrice = orderPrice;
                                LastOrderType = ORDER_TYPE_SELL;
                                break;
                            }
                        }
                        else
                        {
                            if(SendOrder(SymbolName, ORDER_TYPE_SELL, OrderSize, orderPrice,
                                orderPrice + (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount))
                            {
                                for(int i = 1; i < OrderCount; i++)
                                {
                                    SendOrder(SymbolName, ORDER_TYPE_SELL, OrderSize, orderPrice,
                                        orderPrice + (StopLevel + spread) * SymbolInfoDouble(SymbolName, SYMBOL_POINT), errorCount);
                                }
                                LastOrderPrice = orderPrice;
                                LastOrderType = ORDER_TYPE_SELL;
                                break;
                            }
                        }
                        
                        currentPrice = (CurrentBid + CurrentAsk) / 2.0;
                        priceDiff = MathAbs(currentPrice - masterPrice);
                    }
                }
                
                if(LastOrderPrice != -1.0)
                    Print("订单已开仓，价格: ", LastOrderPrice);
            }
            
            // 检查是否应该平仓
            if(LastOrderPrice != -1.0)
            {
                double currentPrice = (CurrentBid + CurrentAsk) / 2.0;
                double point = SymbolInfoDouble(SymbolName, SYMBOL_POINT);
                
                if((masterPrice - currentPrice <= point * MagicNumber && LastOrderType == ORDER_TYPE_BUY) ||
                   (currentPrice - masterPrice <= point * MagicNumber && LastOrderType == ORDER_TYPE_SELL) ||
                   (LastOrderPrice - currentPrice > point * PipsThreshold && LastOrderType == ORDER_TYPE_BUY) ||
                   (currentPrice - LastOrderPrice > point * PipsThreshold && LastOrderType == ORDER_TYPE_SELL))
                {
                    Log(StringFormat("平仓 - 主价格: %.5f, 从价格: %.5f, 延迟: %.5f",
                        masterPrice, currentPrice, currentPrice - masterPrice));
                        
                    for(int i = 0; i < 600; i++)
                    {
                        if(CloseOpenOrders(SymbolName, CalculateMagicNumber(ExpertHash)))
                            break;
                        Sleep(100);
                    }
                    LastOrderPrice = -1.0;
                }
            }
        }
        LastPriceUpdateCount = fileSize;
    }
    
    FileClose(fileHandle);
    Sleep(100);
}

//+------------------------------------------------------------------+
//| 计算订单识别用的魔术数字                                         |
//+------------------------------------------------------------------+
int CalculateMagicNumber(int baseNumber)
{
    for(int i = StringLen(ExpertName); i > 0; i--)
        baseNumber += StringGetCharacter(ExpertName, i);
    return baseNumber;
}

//+------------------------------------------------------------------+
//| 关闭指定交易品种的所有订单                                       |
//+------------------------------------------------------------------+
bool CloseOpenOrders(string symbol, int magic)
{
    bool result = true;
    int total = PositionsTotal();
    
    for(int i = total - 1; i >= 0; i--)
    {
        if(PositionSelectByTicket(PositionGetTicket(i)))
        {
            if(PositionGetInteger(POSITION_MAGIC) != magic || 
               PositionGetString(POSITION_SYMBOL) != symbol)
                continue;
                
            Print("正在平仓: ", PositionGetTicket(i));
            
            // 平仓
            CTrade trade;
            if(!trade.PositionClose(PositionGetTicket(i)))
            {
                Print("平仓错误: ", GetLastError());
                result = false;
            }
        }
    }
    
    return result;
}

//+------------------------------------------------------------------+
//| 发送新订单                                                       |
//+------------------------------------------------------------------+
bool SendOrder(string symbol, ENUM_ORDER_TYPE orderType, double lots, 
               double price, double stopLoss, int &errorCount)
{
    // 检查账户余额
    if(AccountInfoDouble(ACCOUNT_BALANCE) < RiskThreshold)
    {
        errorCount += 10;
        return false;
    }
    
    // 准备交易对象
    CTrade trade;
    trade.SetDeviationInPoints(0);
    trade.SetTypeFilling(ORDER_FILLING_FOK);
    
    // 设置订单参数
    double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
    double adjustedPrice = price - PriceAdjustment * point;
    double adjustedStopLoss = stopLoss;
    
    if(UseECN)
        adjustedStopLoss = 0;
        
    // 发送订单
    bool result = false;
    if(orderType == ORDER_TYPE_BUY)
        result = trade.Buy(lots, symbol, adjustedPrice, adjustedStopLoss, 0, ExpertName);
    else
        result = trade.Sell(lots, symbol, adjustedPrice, adjustedStopLoss, 0, ExpertName);
    
    if(!result)
    {
        Print("发送订单错误: ", GetLastError());
        errorCount++;
        return false;
    }
    
    // 为ECN账户添加止损
    if(UseECN)
        AddStopLoss(trade.ResultOrder(), stopLoss);
        
    return true;
}

//+------------------------------------------------------------------+
//| 为现有订单添加止损                                               |
//+------------------------------------------------------------------+
void AddStopLoss(ulong ticket, double stopLoss)
{
    CTrade trade;
    for(int i = 0; i < 5; i++)
    {
        if(trade.OrderModify(ticket, 0, stopLoss, 0, 0, 0, 0))
            break;
        Sleep(300);
    }
}

//+------------------------------------------------------------------+
//| 获取基础货币的自由保证金                                         |
//+------------------------------------------------------------------+
double GetFreeMarginInBaseCurrency()
{
    double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
    return ConvertToBaseCurrency(freeMargin);
}

//+------------------------------------------------------------------+
//| 将金额转换为基础货币                                             |
//+------------------------------------------------------------------+
double ConvertToBaseCurrency(double amount)
{
    string baseCurrency = StringSubstr(SymbolName, 3, 3);
    string accountCurrency = AccountInfoString(ACCOUNT_CURRENCY);
    
    if(StringFind(accountCurrency, baseCurrency) == -1)
    {
        string conversionSymbol = baseCurrency + accountCurrency + SymbolSuffix;
        if(SymbolInfoDouble(conversionSymbol, SYMBOL_ASK) != 0.0)
            amount /= SymbolInfoDouble(conversionSymbol, SYMBOL_ASK);
        else
            amount /= 1 / SymbolInfoDouble(accountCurrency + baseCurrency + SymbolSuffix, SYMBOL_ASK);
    }
    
    return amount;
}

//+------------------------------------------------------------------+
//| 检查是否使用固定最大订单大小                                     |
//+------------------------------------------------------------------+
bool IsFixedMaxOrderSize()
{
    if(SymbolInfoDouble("AUDUSD" + SymbolSuffix, SYMBOL_MARGIN_INITIAL) == 
       SymbolInfoDouble("USDJPY" + SymbolSuffix, SYMBOL_MARGIN_INITIAL) && 
       SymbolInfoDouble("AUDUSD" + SymbolSuffix, SYMBOL_MARGIN_INITIAL) == 
       SymbolInfoDouble("EURUSD" + SymbolSuffix, SYMBOL_MARGIN_INITIAL))
        return true;
    return false;
}

//+------------------------------------------------------------------+
//| 计算最大订单大小                                                 |
//+------------------------------------------------------------------+
double GetMaxOrderSize(int priceType)
{
    if(StringLen(SymbolName) == 7)
        SymbolSuffix = ".";
        
    int stopLevel = (int)SymbolInfoInteger(SymbolName, SYMBOL_TRADE_STOPS_LEVEL);
    double point = SymbolInfoDouble(SymbolName, SYMBOL_POINT);
    double price = 0;
    
    switch(priceType)
    {
        case 4: price = SymbolInfoDouble(SymbolName, SYMBOL_ASK) + stopLevel * point; break;
        case 5: price = SymbolInfoDouble(SymbolName, SYMBOL_BID) - stopLevel * point; break;
        case 0: price = SymbolInfoDouble(SymbolName, SYMBOL_ASK); break;
        case 1: price = SymbolInfoDouble(SymbolName, SYMBOL_BID); break;
    }
    
    double freeMargin = GetFreeMarginInBaseCurrency();
    int leverage = (int)AccountInfoInteger(ACCOUNT_LEVERAGE);
    int lotStep = (int)(1 / SymbolInfoDouble(SymbolName, SYMBOL_VOLUME_STEP));
    int lotSize = 100000;
    
    if(IsFixedMaxOrderSize())
    {
        price = ConvertToBaseCurrency(SymbolInfoDouble(SymbolName, SYMBOL_MARGIN_INITIAL));
        leverage = 100;
        lotSize = 100;
    }
    
    return NormalizeDouble(MathFloor(RiskMultiplier * lotStep * 
           (freeMargin / price / (lotSize / 100) * (leverage / 100))) / lotStep, 2);
}

//+------------------------------------------------------------------+
//| 记录交易信息                                                     |
//+------------------------------------------------------------------+
void Log(string message)
{
    // 实现日志记录功能
    if(DebugMode)
        Print(message);
} 